---
type: tutorial
title: Build your first layout
description: |-
  Tutorial: Build your first Astro blog —
  Refactor common elements into a reusable page layout
i18nReady: true
---
import Box from '~/components/tutorial/Box.astro';
import Checklist from '~/components/Checklist.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import Option from '~/components/tutorial/Option.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';
import { Steps } from '@astrojs/starlight/components';


<PreCheck>
  - Refactor common elements into a page layout
  - Use an Astro `<slot />` element to place page contents within a layout
  - Pass page-specific values as props to its layout
</PreCheck>

You still have some Astro components repeatedly rendered on every page. It's time to refactor again to create a shared page layout!

## Create your first layout component

<Steps>
1. Create a new file at the location `src/layouts/BaseLayout.astro`. (You will need to create a new `layouts` folder first.)

2. Copy the **entire contents** of `index.astro` into your new file, `BaseLayout.astro`.

    ```astro title="src/layouts/BaseLayout.astro"
    ---
    import Header from '../components/Header.astro';
    import Footer from '../components/Footer.astro';
    import '../styles/global.css';
    const pageTitle = "Home Page";
    ---
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
        <meta name="viewport" content="width=device-width" />
        <meta name="generator" content={Astro.generator} />
        <title>{pageTitle}</title>
      </head>
      <body>
        <Header />
        <h1>{pageTitle}</h1>
        <Footer />
        <script>
          import "../scripts/menu.js";
        </script>
      </body>
    </html>
    ```
</Steps>

## Use your layout on a page

<Steps>
3. Replace the code at `src/pages/index.astro` with the following:

    ```astro title="src/pages/index.astro"
    ---
    import BaseLayout from '../layouts/BaseLayout.astro';
    const pageTitle = "Home Page";
    ---
    <BaseLayout>
      <h2>My awesome blog subtitle</h2>
    </BaseLayout>
    ```
 
4. Check the browser preview again to notice what did (or, spoiler alert: did _not_!) change.
    
5. Add a `<slot />` element to `src/layouts/BaseLayout.astro` just above the footer component, then check the browser preview of your Home page and notice what really _did_ change this time!

    ```astro title="src/layouts/BaseLayout.astro" ins={18}
    ---
    import Header from '../components/Header.astro';
    import Footer from '../components/Footer.astro';
    import '../styles/global.css';
    const pageTitle = "Home Page";
    ---
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
        <meta name="viewport" content="width=device-width" />
        <meta name="generator" content={Astro.generator} />
        <title>{pageTitle}</title>
      </head>
      <body>
        <Header />
        <h1>{pageTitle}</h1>
        <slot />
        <Footer />
        <script>
          import "../scripts/menu.js";
        </script>
      </body>
    </html>
    ```
</Steps>

 The `<slot />` allows you to inject (or "slot in") **child content** written between opening and closing `<Component></Component>` tags to any `Component.astro` file.

## Pass page-specific values as props

<Steps>
6. Pass the page title to your layout component from `index.astro` using a component attribute: 

    ```astro title="src/pages/index.astro" 'pageTitle={pageTitle}'
    ---
    import BaseLayout from '../layouts/BaseLayout.astro';
    const pageTitle = "Home Page";
    ---
    <BaseLayout pageTitle={pageTitle}>
      <h2>My awesome blog subtitle</h2>
    </BaseLayout>
    ```

7. Change the script of your `BaseLayout.astro` layout component to receive a page title via `Astro.props` instead of defining it as a constant.

    ```astro title="src/layouts/BaseLayout.astro" del={5} ins={6}
    ---
    import Header from '../components/Header.astro';
    import Footer from '../components/Footer.astro';
    import '../styles/global.css';
    const pageTitle = "Home Page";
    const { pageTitle } = Astro.props;
    ---
    ```

8. Check your browser preview to verify that your page title has not changed. It has the same value, but is now being rendered dynamically. And now, each individual page can specify its own title to the layout.
</Steps>

<Box icon="puzzle-piece">

## Try it yourself - Use your layout everywhere

**Refactor** your other pages (`blog.astro` and `about.astro`) so that they use your new `<BaseLayout>` component to render the common page elements.

Don't forget to:

- Pass a page title as props via a component attribute.

- Let the layout be responsible for the HTML rendering of any common elements.

- Delete anything from each page that that page is no longer responsible for rendering, because it is being handled by the layout, including: 

  - HTML elements
  - Components and their imports 
  - CSS rules in a `<style>` tag (e.g. `<h1>` in your About page)
  - `<script>` tags
</Box>



<Box icon="question-mark">

### Test your knowledge

1. An Astro component (`.astro` file) can function as a:

    <MultipleChoice>
      <Option>page</Option>
      <Option>UI component</Option>
      <Option>layout</Option>
      <Option isCorrect>all of the above, because Astro components are so functional! 🏗️</Option>
    </MultipleChoice>

2. To display a page title on the page, you can:

    <MultipleChoice>
      <Option>
        use a standard HTML element on the page with static text (e.g `<h1>Home Page</h1>`)
      </Option>
      <Option>
        use a standard HTML element on the page referring to a variable defined in your component's frontmatter script (e.g. `<h1>{pageTitle}</h1>`)
      </Option>
      <Option>
        use a layout component on the page, passing the title as a component attribute (e.g. `<BaseLayout title="Home Page" />` or `<BaseLayout title={pageTitle} />`)
      </Option>
      <Option isCorrect>
        all of the above, because Astro lets you use plain HTML or supercharge it with some script and components! 💪
      </Option>
    </MultipleChoice>

3. Information can be passed from one component to another by:

    <MultipleChoice>
      <Option>
        importing a UI component and rendering it in the template of another component
      </Option>
      <Option>
        passing props to a component where it is rendered via a component attribute
      </Option>
      <Option>
        sending HTML content to be rendered inside another component using a `<slot />` placeholder
      </Option>
      <Option isCorrect>
        all of the above, because Astro was built to take advantage of component-based design! 🧩
      </Option>
    </MultipleChoice>

</Box>

<Box icon="check-list">

## Checklist

<Checklist>
- [ ] I can create an Astro layout component with a `<slot />`.
- [ ] I can send page-specific properties to a layout.
</Checklist>
</Box>

### Resources

- [Astro layout components](/en/basics/layouts/)

- [Astro `<slot />`](/en/basics/astro-components/#slots)
